Silverlight: Binding and Threading == Cat and Dog

Introduction

Let me start by thanking Ian Griffiths for the brilliant course that he delivered to me in London this week on Silverlight. Ian you’re the man!!! Ok having said that we can now start 🙂

Just like in WPF, threading and databinding in Silverlight have a Cat – Dog relationship. This is due to the fact that when a binding notification is raised from a separate thread than the Dispatcher thread, an exception is thrown. The exception is thrown because the binding is trying to modify the a UI element from a separate thread than the Dispatcher thread. In Silverlight this is even a bit worse than it is in WPF because an exception is raised even when the notification is from an INotifyPropertyChanged. Another miss leading thing in Silverlight is that, the exception thrown when a binding notification is raised from a separate thread is of type System.UnauthorizedAccessException (you can see this in the Visual Studio Output window). Hmmm … We WPF guys are used to see the InvalidOperationException for this but anyway…

Ok so till now we determined that both INotifyPropertyChanged and INotifyCollectionChanged will explode if they raise the binding notification from a separate thread than the UI thread so let’s see how to work around this.

In WPF one can get the Dispatcher instance by calling Application.Current.Dispatcher or by saying Dispatcher.CurrentDispatcher but guess what; both of these are not included in Silverlight. Don’t worry we still can get Mr. Dispatcher, we need to call the Application.Current.RootVisual.Dispatcher (keeping in mind not to call RootVisual from a seperate thread than the Dispatcher thread otherwise BAMMMM).

Brilliant, we have the dispatcher but guess what the only method that you can see (in the VS intellisense) in the Dispatcher is BeginInvoke !! This will not help much since we need a CheckAccess method that can check for us if the executing thread is the dispatcher thread. After drilling into the Dispatcher class, I found that a CheckAccess method actually exits in the Dispatcher class but for some strange reason it is decorated with this attribute -> [EditorBrowsable(EditorBrowsableState.Never)] to hide it from us developers. I guess this means that it is subject to change in the very near future …

Anyway, now that we know how to get the Dispatcher instance and how to check if the executing thread is the dispatcher thread we can get to work. Lets’ start by fixing the INotifyPropertyChanged issue.

Fixing INotifyPropertyChanged

This will be quite easy, we will need to make the object raise the binding notification on the dispatcher thread. I created a base class that will do this for you… It is very simple have a look yourself.

/// <summary>
/// Base class for objects that need to raise property change notification from seperate threads
/// </summary>
public abstract class ThreadableBindableObject : INotifyPropertyChanged
{
    private Dispatcher currentDispatcher;
 
    /// <summary>
    /// default constructor
    /// Here we must get the Dispatcher object
    /// </summary>
    public ThreadableBindableObject()
    {
        if (Application.Current != null &&
                                Application.Current.RootVisual != null &&
                                Application.Current.RootVisual.Dispatcher != null)
        {
            currentDispatcher = Application.Current.RootVisual.Dispatcher;
        }
        else // if we did not get the Dispatcher throw an exception
        {
            throw new InvalidOperationException("This object must be initialized after that the RootVisual has been loaded");
        }
 
    }
 
    #region INotifyPropertyChanged Members
 
    /// <summary>
    /// Event raised to notify listeners that a property changed
    /// </summary>
    public event PropertyChangedEventHandler PropertyChanged;
 
    /// <summary>
    /// raises the PropertyChanged on the dispatcher thread
    /// This will only switch to the Dispatcher thread if the Dispatcher is available via the RootVisual
    /// </summary>
    /// <param name="propertyName">The property name to raise the event</param>
    protected void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            //check if we are on the UI thread if not switch
            if (currentDispatcher.CheckAccess())
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            else
                currentDispatcher.BeginInvoke(new Action<string>(OnPropertyChanged), propertyName);
        }
    }
 
    #endregion
}

 

So basically this base class will go ahead and implement the INotifyPropertyChanged interface for you and make sure that before the PropertyChanged event is raised we are on the Dispatcher thread. One would ask why are we getting the dispatcher instance in the constructor of the object, well the answer is that, we cannot get the Dispatcher instance from the OnPropertyChanged method because that method will be called from non dispatcher threads and if you call the Application.Current.RootVisual from a non dispatcher thread BAMMM… everything explodes because you are trying to access a UI element from a non dispatcher thread. Ok so now that we have this class we can go ahead and use it by inheriting from it; something like this I would say

public class Person : ThreadableBindableObject
{
    private string name;
 
    public string Name
    {
        get { return name; }
        set
        {
            name = value;
            OnPropertyChanged("Name");
        }
    }
 
    private string surname;
 
    public string Surname
    {
        get { return surname; }
        set
        {
            surname = value;
            OnPropertyChanged("Surname");
        }
    }
}

 

Fixing INotifyCollectionChanged

When it comes to the INotifyCollectionChanged we want to avoid to re invent the wheel and implement the INotifyCollectionChanged interface ourselves so what we are going to do is to inherit from the ObservableCollection<T> and override the base methods for the Insert, Remove, Clear and Set. We will also need to override the OnPropertyChanged. This is nothing new, Beatriz Costa the WPF Queen, did this a while ago in the WPF world so; NO, I am not inventing anything here I am just being a messenger 🙂

So here is the code for the new ObservableCollection… I called it ThreadableObservableCollection<T> so that it sounds complex 😀

/// <summary>
/// Collection that supports INotifyCollectionChanged notification from seperate threads
/// </summary>
/// <typeparam name="T">The type of object to store in the collections</typeparam>
public class ThreadableObservableCollection<T> : ObservableCollection<T>
{
    private Dispatcher currentDispatcher;
 
    /// <summary>
    /// default constructor
    /// Here we must get the Dispatcher object
    /// </summary>
    public ThreadableObservableCollection()
    {
        if (Application.Current != null &&
                                Application.Current.RootVisual != null &&
                                Application.Current.RootVisual.Dispatcher != null)
        {
            currentDispatcher = Application.Current.RootVisual.Dispatcher;
        }
        else // if we did not get the Dispatcher throw an exception
        {
            throw new InvalidOperationException("This object must be initialized after that the RootVisual has been loaded");
        }
    }
 
    protected override void InsertItem(int index, T item)
    {
        if (currentDispatcher.CheckAccess())
            base.InsertItem(index, item);
        else
            currentDispatcher.BeginInvoke(new Action<int, T>(InsertItem), index, item);
    }
 
    protected override void ClearItems()
    {
        if (currentDispatcher.CheckAccess())
            base.ClearItems();
        else
            currentDispatcher.BeginInvoke(new Action(ClearItems));
    }
 
    protected override void RemoveItem(int index)
    {
        if (currentDispatcher.CheckAccess())
            base.RemoveItem(index);
        else
            currentDispatcher.BeginInvoke(new Action<int>(RemoveItem), index);
    }
 
    protected override void SetItem(int index, T item)
    {
        if (currentDispatcher.CheckAccess())
            base.SetItem(index, item);
        else
            currentDispatcher.BeginInvoke(new Action<int, T>(SetItem), index, item);
    }
 
    protected override void OnPropertyChanged(PropertyChangedEventArgs e)
    {
        if (currentDispatcher.CheckAccess())
            base.OnPropertyChanged(e);
        else
            currentDispatcher.BeginInvoke(new Action<PropertyChangedEventArgs>(OnPropertyChanged), e);
    }
}

As you can see there is nothing to it. We are just overriding the base methods Insert, Remove, Clear and Set so that we make sure that they will get called on the Dispatcher thread. These methods are the methods that raise the CollectionChanged event so by forcing them to run on the Dispatcher thread we are ensuring that the binding will potentially work (hihi … what a paradox). We are also doing this for the OnPropertyChanged method of course.

Conclusion

Yea, the conclusion is threading can be pain full especially when dealing with UI but that’s life 🙂

 

Download Sample Source

26 thoughts on “Silverlight: Binding and Threading == Cat and Dog

  1. Another area where SL differs from WPF (WPF takes care of mashaling automatically), just one note, every control indeed exposes Dispatcher property and this is fully accessible even from secondary threads.

  2. hey there,

    yes WPF does handle it for INotifyPropertyChanged… There is a problem with accessing the dispatcher from a seperate thread . in fact if you call Application.Current.RootVisual from a seperate thread BAMM it explodes 😀

    Regards

  3. Great post.. Multi-threading seems more trouble than it’s worth! I’m still yet to play with the dispatcher and worker thread stuff BUT it’s things like this that scare me away.

    From your experience is it worth the trouble? Having multi-threads that is? Why not just use the single UI thread with async capabilities for things running in it?

    ps. i know the future lies in multi-threading especially with multi-core processors quickly becoming the norm BUT just the thought of coding multi-threads makes me want to pack up and live on some remote beach somewhere 🙂

  4. Hi Marlon,
    Accessing Application.Current.RootVisual from a secondary thread is not allowed, but if you do something like button1.Dispatcher.BeginInvoke(…) from a secondary thread it works fine.

  5. Pingback: Robs Usability Development : Silverlight, ASP.NET, Ajax, Agile, MVC & Volta - NL » Updating the UI Thread in Silverlight 2

  6. A great article! I was really searching a lot how can I modify the the DataGrid UI from other threads.
    But there are were a couple of problems of which I came across, which I think is a bug in the DataGrid control.
    First as from my project I had an Async socket read which was going very fast and somehow the I was getting InvokeMethodFast exceptions … Unfortunatly I cannot set the Invoke priority for setting items in my Collection 😦 Also another one which I think is a problem in the DataGrid, everyone works fine when you Add/Remove elements, but if you replace elements then you get a method not supported exception of type NotifyCollection changed.
    But anyhow lot’s of thanks for the insight into the threading mechanism in silverlight 🙂

  7. Hi
    I have used ThreadableObservableCollection in my project.
    I have used Dispatcher Timer to add Items in to the ThreadableObservableCollection. I am getting exception in the following line.
    base.SetItem(index, item);

    InvalidOperationException: Cannot change ObservableCollection during a CollectionChanged or PropertyChanged event.

    Here is my sample project.
    http://rapidshare.com/files/146040964/ControlTest.zip.html

    Please Help.

  8. Hi Marlon,

    I’m a bit late to comment this post, but I’ll do it anyway 😉

    If retrieving the current Dispatcher is such a pain in Silverlight, why not use the SynchronizationContext instead of the Dispatcher ? You can retrieve it with SynchronizationContext.Current, and then use Post or Send to perform the action on the UI thread.

    I wrote a solution similar to yours, based on the SynchronizationContext, which can be found here :
    http://tomlev2.wordpress.com/2009/04/17/wpf-binding-to-an-asynchronous-collection/

  9. Relevé systématique des baptêmes ou naissances, mariages motercalo sépultures relevé systématique de nivillac. relevé des tables décennales nivillac 1802 .

  10. Hello friends,

    My name is enrobeled, I just wanted to say hello and present myself.
    I am an independent writer and depending on my time I will more or less be contributing to this community.
    I particularily enjoy sharing amazing stories found in the internet and get that really special content out of there.

    See you/read you around!

    enrobeled

  11. [i]Weight loss[/i] is a reduction of[i] body weight[/i] that is triggered by exercise, dieting or an involuntary condition such as an illness. As it is well known when the body does not get enough calories it starts to burn the fat that was deposited in the fat tissue. Normal intake of calories for a human being is about 1800-2200 calories a day. One gram of burned fat produces 9 calories so it is easy to count how much fat are you burning when you lower your calories intake.

    Dieting or voluntary [i]weight loss[/i] nowadays is very common for people with [i]health problems[/i] like obesity, heart dysfunction or for people who might not necessarily need it but want to look good. Weight loss or even fast weight loss may be caused by illness that are associated with such severe conditions like:

    * Cancer
    * Chronic diarrhea
    * Chronic inflammation

    Obesity is a condition of extreme overweight when the body mass index or BMI is above 30. Or for people with over risk factors as hypertension or diabetes above 27. The weight loss drugs used for fighting obesity is most commonly given only by prescription and should not be used without doctors supravision. Most of the weight loss drugs work by suppressing the appetite only a few like Xenical have different therapeutic action.

  12. скачать книгу санитары подземелий, скачать неистовый зверь мой, скачать песню rob dougan

  13. потап и настя разгуляй скачать, icq для wm 6.1 скачать, бутырка remix скачать

Leave a comment